home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr05 / xnot12a.zip / DISPLAY.C < prev    next >
C/C++ Source or Header  |  1993-06-16  |  31KB  |  1,181 lines

  1. #include "jam.h"
  2. /*
  3.  * The functions in this file handle redisplay. The
  4.  * redisplay system knows almost nothing about the editing
  5.  * process; the editing functions do, however, set some
  6.  * hints to eliminate a lot of the grinding. There is more
  7.  * that can be done; the "vtputc" interface is a real
  8.  * pig. Two conditional compilation flags; the GOSLING
  9.  * flag enables dynamic programming redisplay, using the
  10.  * algorithm published by Jim Gosling in SIGOA.
  11.  *
  12.  * NOTE that GOSLING is best used when emacs is running on some
  13.  * BIG cpu and sending characters over a wire to a tty device.
  14.  * GOSLING is very compute intensive! Note also that for MS Windows
  15.  * versions (cpu and display in one box) it is FAR better to turn
  16.  * GOSLING off and use WINDOW_IO which assumes char string output
  17.  * is very cheap. On Windows 3.1, it is probably twice as fast
  18.  * as opposed to using GOSLING w/o WINDOW_IO defined. (JAM)
  19.  *
  20.  */
  21. #include "def.h"
  22. #include "kbd.h"
  23. #include <stdio.h>
  24. #include <malloc.h>
  25. #include <string.h>
  26.  
  27. #define LINECOLOR(lp)\
  28.         (showtouchedlines && (lp->l_flag & LFCHANGE) ? CHIGH : CTEXT)
  29. /*
  30.  * You can change these back to the types
  31.  * implied by the name if you get tight for space. If you
  32.  * make both of them "int" you get better code on the VAX.
  33.  * They do nothing if this is not Gosling redisplay, except
  34.  * for change the size of a structure that isn't used.
  35.  * A bit of a cheat.
  36.  */
  37.  
  38. #define XCHAR char
  39. #define XSHORT short
  40.  
  41. /* These defines really belong in sysdef.h 
  42. */
  43. #ifndef XCHAR
  44. #  define    XCHAR    int
  45. #  define    XSHORT    int
  46. #endif
  47.  
  48. #ifdef    STANDOUT_GLITCH
  49.   extern int SG;            /* number of standout glitches    */
  50. #endif
  51.  
  52. /*
  53.  * A video structure always holds
  54.  * an array of characters whose length is equal to
  55.  * the longest line possible. Only some of this is
  56.  * used if "ncol" isn't the same as "NCOL".
  57.  */
  58. typedef struct    video_{
  59. #ifdef GOSLING
  60.     short    v_hash;            /* Hash code, for compares.    */
  61.     XSHORT    v_cost;            /* Cost of display.        */
  62. #endif
  63.     char    v_flag;            /* Flag word.            */
  64.     char    v_color;        /* Color of the line.        */
  65.     char    v_text[NCOL];        /* The actual characters.    */
  66. }    VIDEO;
  67.  
  68. #define VFCHG    0x0001            /* Changed.            */
  69. #define VFHBAD    0x0002            /* Hash and cost are bad.    */
  70. #define VFEXT    0x0004            /* extended line (beond ncol)    */
  71.  
  72. /*
  73.  * SCORE structures hold the optimal
  74.  * trace trajectory, and the cost of redisplay, when
  75.  * the dynamic programming redisplay code is used.
  76.  * If no fancy redisplay, this isn't used. The trace index
  77.  * fields can be "char", and the score a "short", but
  78.  * this makes the code worse on the VAX.
  79.  */
  80. typedef struct    {
  81.     XCHAR    s_itrace;        /* "i" index for track back.    */
  82.     XCHAR    s_jtrace;        /* "j" index for trace back.    */
  83.     XSHORT    s_cost;            /* Display cost.        */
  84. }    SCORE;
  85.  
  86. /* Blah - these are all globals but originate here. I hate
  87. * that but am not going to move them in the interest of
  88. * preserving the code's history (JAM)
  89. */
  90. int sgarbf = TRUE;        /* TRUE if screen is garbage.    */
  91. int vtrow = 0;            /* Virtual cursor row.        */
  92. int vtcol = 0;            /* Virtual cursor column.    */
  93. int tthue = CNONE;        /* Current color.        */
  94. int ttrow = HUGEN;        /* Physical cursor row.        */
  95. int ttcol = HUGEN;        /* Physical cursor column.    */
  96. int tttop = HUGEN;        /* Top of scroll region.    */
  97. int ttbot = HUGEN;        /* Bottom of scroll region.    */
  98.  
  99. static int lbound = 0;        /* leftmost bound of the current line
  100.                    being displayed */
  101.  
  102. /* virtual and physical screen arrays
  103. */
  104. #ifndef GOSLING
  105.  static VIDEO *vscreen;        /* Edge vector, virtual.    */
  106.  static VIDEO *pscreen;        /* Edge vector, physical.    */
  107. #else
  108. # define STATIC static
  109. # ifdef MSW        /* problems with 64k data seg limits */
  110. #  ifndef WIN32
  111. #   undef STATIC
  112. #   define STATIC 
  113. #  endif
  114. # endif
  115.  STATIC VIDEO *vscreen[NROW-1];    /* Edge vector, virtual.    */
  116.  STATIC VIDEO *pscreen[NROW-1];    /* Edge vector, physical.    */
  117.  STATIC VIDEO video[2*(NROW-1)];/* Actual screen data.        */
  118. #endif
  119. static VIDEO *blanks;        /* Blank line image.        */
  120.  
  121. static VOID rn_(ucopy,(VIDEO *vvp, VIDEO *pvp)); 
  122. static VOID rn_(uline,(int row, VIDEO *vvp, VIDEO *pvp));
  123. static void rn_(modeline,(EWINDOW *wp, BOOL activebp));
  124. static int rn_(vtputb, (char c, int n));
  125.  
  126. #ifdef GOSLING
  127.  static VOID rn_(hash,(VIDEO *vp));
  128.  static VOID rn_(setscores,(int offs, int size));
  129.  static VOID rn_(traceback,(int offs, int size, int i, int j));
  130.  
  131.  /*
  132.   * This matrix is written as an array because
  133.   * we do funny things in the "setscores" routine, which
  134.   * is very compute intensive, to make the subscripts go away.
  135.   * It would be "SCORE    score[NROW][NROW]" in old speak.
  136.   * Look at "setscores" to understand what is up.
  137.   */
  138.  static SCORE score[NROW*NROW];
  139. #endif
  140.  
  141. /*
  142.  * Initialize the data structures used
  143.  * by the display code. The edge vectors used
  144.  * to access the screens are set up. The operating
  145.  * system's terminal I/O channel is set up. Fill the
  146.  * "blanks" array with ASCII blanks. The rest is done
  147.  * at compile time. The original window is marked
  148.  * as needing full update, and the physical screen
  149.  * is marked as garbage, so all the right stuff happens
  150.  * on the first call to redisplay.
  151.  */
  152. VOID vtinit() 
  153. {
  154. #ifdef GOSLING
  155.     register VIDEO    *vp;
  156. #endif
  157.     register int    i;
  158.  
  159.     ttopen();
  160.     ttinit();
  161. #ifndef GOSLING
  162.         /* Array indirection different when not doing
  163.         * cost computation; arrays allocated vs static
  164.         * and max size of screen (NROWs) can now be larger
  165.         * since vscreen & pscreen don't point into single array
  166.         * (why was that done anyway?? and I can fix that outside
  167.         * the GOSLING thing if I want but didn't bother since
  168.         * not using GOSLING anyways) (JAM)
  169.         */
  170.         vscreen = (VIDEO *)calloc(NROW-1, sizeof(VIDEO));
  171.         pscreen = (VIDEO *)calloc(NROW-1, sizeof(VIDEO));
  172. #else
  173.     vp = &video[0];
  174.     for (i=0; i<NROW-1; ++i) {
  175.         vscreen[i] = vp;
  176.         ++vp;
  177.         pscreen[i] = vp;
  178.         ++vp;
  179.     }
  180. #endif
  181.         blanks = (VIDEO *)calloc(1, sizeof(VIDEO));
  182.     blanks->v_color = CTEXT;
  183.     for (i=0; i<NCOL; ++i)
  184.       blanks->v_text[i] = ' ';
  185. }
  186.  
  187. /*
  188.  * Tidy up the virtual display system
  189.  * in anticipation of a return back to the host
  190.  * operating system. Right now all we do is position
  191.  * the cursor to the last line, erase the line, and
  192.  * close the terminal channel.
  193.  *
  194.  * Free memory allocted for VIDEO's if not GOSLING.
  195.  */
  196. VOID vttidy() {
  197.     ttcolor(CTEXT);
  198.     ttnowindow();                /* No scroll window.    */
  199.     ttmove(nrow-1, 0);            /* Echo line.        */
  200.     tteeol();
  201.     tttidy();
  202.     ttflush(FALSE);
  203.     ttclose();
  204. #ifndef GOSLING
  205.         free(vscreen);
  206.         free(pscreen);
  207.         free(blanks);
  208. #endif
  209. }
  210.  
  211. /*
  212.  * Move the virtual cursor to an origin
  213.  * 0 spot on the virtual display screen. I could
  214.  * store the column as a character pointer to the spot
  215.  * on the line, which would make "vtputc" a little bit
  216.  * more efficient. No checking for errors.
  217.  */
  218. VOID vtmove(row, col) 
  219. int row, col;
  220. {
  221.   vtrow = row;
  222.   vtcol = col;
  223. }
  224.  
  225. /*
  226.  * Write a character to the virtual display,
  227.  * dealing with long lines and the display of unprintable
  228.  * things like control characters. Also expand tabs every TABSTOP
  229.  * columns. This code only puts printing characters into
  230.  * the virtual display image. Special care must be taken when
  231.  * expanding tabs. On a screen whose width is not a multiple
  232.  * of TABSTOP, it is possible for the virtual cursor to hit the
  233.  * right margin before the next tab stop is reached. This
  234.  * makes the tab code loop if you are not careful.
  235.  * Three guesses how we found this.
  236.  */
  237. VOID vtputc(c) 
  238. register int c; 
  239. {
  240.     register VIDEO    *vp;
  241.  
  242. #ifndef GOSLING
  243.     vp = &vscreen[vtrow];
  244. #else
  245.     vp = vscreen[vtrow];
  246. #endif
  247.     if (vtcol >= ncol)
  248.       vp->v_text[ncol-1] = '$';
  249.     else if (c == '\t') 
  250.           {
  251.         do {
  252.           vtputc(' ');
  253.            } while (vtcol<ncol && (vtcol&TABROUND)!=0);
  254.       } 
  255.         else if (ISCTRL(c)) 
  256.           {
  257.         vtputc('^');
  258.         vtputc(CCHR(c));
  259.       } 
  260.         else
  261.       vp->v_text[vtcol++] = (char)c;
  262. }
  263.  
  264. /* Put a character to the virtual screen in an extended line.  If we are
  265.  * not yet on left edge, don't print it yet.  Check for overflow on
  266.  * the right margin.
  267.  */
  268. VOID vtpute(c)
  269. int c;
  270. {
  271.     register VIDEO    *vp;
  272.  
  273. #ifndef GOSLING
  274.     vp = &vscreen[vtrow];
  275. #else
  276.     vp = vscreen[vtrow];
  277. #endif
  278.  
  279.     if (vtcol >= ncol) vp->v_text[ncol - 1] = '$';
  280.     else if (c == '\t') {
  281.     do {
  282.         vtpute(' ');
  283.     }
  284.     while (((vtcol + lbound)&TABROUND) != 0 && vtcol < ncol);
  285.     } else if (ISCTRL(c) != FALSE) {
  286.     vtpute('^');
  287.     vtpute(CCHR(c));
  288.     } else {
  289.     if (vtcol >= 0) 
  290.       vp->v_text[vtcol] = (char)c;
  291.     ++vtcol;
  292.     }
  293. }
  294.  
  295. /* Erase from the end of the
  296.  * software cursor to the end of the
  297.  * line on which the software cursor is
  298.  * located. The display routines will decide
  299.  * if a hardware erase to end of line command
  300.  * should be used to display this.
  301.  */
  302. VOID vteeol() 
  303. {
  304.     register VIDEO    *vp;
  305.  
  306. #ifndef GOSLING
  307.     vp = &vscreen[vtrow];
  308. #else
  309.     vp = vscreen[vtrow];
  310. #endif
  311.     while (vtcol < ncol)
  312.         vp->v_text[vtcol++] = ' ';
  313. }
  314.  
  315. /*
  316.  * Make sure that the display is
  317.  * right. This is a three part process. First,
  318.  * scan through all of the windows looking for dirty
  319.  * ones. Check the framing, and refresh the screen.
  320.  * Second, make sure that "currow" and "curcol" are
  321.  * correct for the current window. Third, make the
  322.  * virtual and physical screens the same.
  323.  */
  324. VOID update() 
  325. {
  326.     register LINE    *lp;
  327.     register EWINDOW *wp;
  328.     register VIDEO    *vp1;
  329.     VIDEO        *vp2;
  330.     register int    i;
  331.     register int    j;
  332.     register int    c;
  333.         register int    k;
  334.     register int    hflag;
  335.     register int    currow;
  336.     register int    curcol;
  337. #ifdef GOSLING
  338.     register int    offs;
  339.     register int    size;
  340. #endif
  341.     if (mytypeahead()) 
  342.       return;
  343.     if (sgarbf)                 /* must update everything */
  344.           upmodes(WFMODE|WFHARD);
  345.     
  346.     hflag = FALSE;                /* Not hard.        */
  347.     wp = wheadp;
  348.     while (wp != NULL) {
  349.         if (wp->w_flag != 0) {        /* Need update.        */
  350.             if ((wp->w_flag&WFFORCE) == 0) {
  351.                 lp = wp->w_linep;
  352.                 for (i=0; i<wp->w_ntrows; ++i) {
  353.                     if (lp == wp->w_dotp)
  354.                         goto out;
  355.                     if (lp == wp->w_bufp->b_linep)
  356.                         break;
  357.                     lp = lforw(lp);
  358.                 }
  359.             }
  360.             i = wp->w_force;    /* Reframe this one.    */
  361.             if (i > 0) {
  362.                 --i;
  363.                 if (i >= wp->w_ntrows)
  364.                     i = wp->w_ntrows-1;
  365.             } else if (i < 0) {
  366.                 i += wp->w_ntrows;
  367.                 if (i < 0)
  368.                     i = 0;
  369.             } else
  370.                 i = wp->w_ntrows/2;
  371.             lp = wp->w_dotp;
  372.             while (i!=0 && lback(lp)!=wp->w_bufp->b_linep) {
  373.                 --i;
  374.                 lp = lback(lp);
  375.             }
  376.             wp->w_linep = lp;
  377.             wp->w_flag |= WFHARD;    /* Force full.        */
  378.         out:
  379.             lp = wp->w_linep;    /* Try reduced update.    */
  380.             i  = wp->w_toprow;
  381.             if ((wp->w_flag&~WFMODE) == WFEDIT) {
  382.                 while (lp != wp->w_dotp) {
  383.                     ++i;
  384.                     lp = lforw(lp);
  385.                 }
  386. #ifndef GOSLING
  387.                 vscreen[i].v_color = LINECOLOR(lp);
  388.                 vscreen[i].v_flag |= (VFCHG|VFHBAD);
  389. #else
  390.                 vscreen[i]->v_color = LINECOLOR(lp);
  391.                 vscreen[i]->v_flag |= (VFCHG|VFHBAD);
  392. #endif
  393.                 vtmove(i, 0);
  394.                 for (j=0; j<llength(lp); ++j)
  395.                     vtputc(lgetc(lp, j));
  396.                 vteeol();
  397.             } else if ((wp->w_flag&(WFEDIT|WFHARD)) != 0) {
  398.                 hflag = TRUE;
  399.                 while (i < wp->w_toprow+wp->w_ntrows) {
  400. #ifndef GOSLING        
  401.                                         vscreen[i].v_color = LINECOLOR(lp);
  402.                     vscreen[i].v_flag |= (VFCHG|VFHBAD);
  403. #else
  404.                     vscreen[i]->v_color = LINECOLOR(lp);
  405.                     vscreen[i]->v_flag |= (VFCHG|VFHBAD);
  406. #endif
  407.                     vtmove(i, 0);
  408.                     if (lp != wp->w_bufp->b_linep) {
  409.                         for (j=0; j<llength(lp); ++j)
  410.                             vtputc(lgetc(lp, j));
  411.                         lp = lforw(lp);
  412.                     }
  413.                     vteeol();
  414.                     ++i;
  415.                 }
  416.             }
  417.             if ((wp->w_flag&WFMODE) != 0)
  418.               modeline(wp, (wp == curwp ? TRUE : FALSE));
  419.             wp->w_flag  = 0;
  420.             wp->w_force = 0;
  421.         }
  422.         wp = wp->w_wndp;
  423.     }
  424.     lp = curwp->w_linep;            /* Cursor location.    */
  425.     currow = curwp->w_toprow;
  426.     while (lp != curwp->w_dotp) {
  427.         ++currow;
  428.         lp = lforw(lp);
  429.     }
  430.     curcol = 0;
  431.     i = 0;
  432.     while (i < curwp->w_doto) {
  433.         c = lgetc(lp, i++);
  434.         if (c == '\t') 
  435.           curcol |= TABROUND;
  436.         else if (ISCTRL(c) != FALSE)
  437.             ++curcol;
  438.         ++curcol;
  439.     }
  440.     if (curcol >= ncol - 1) {        /* extended line. */
  441.          /* flag we are extended and changed */
  442. #ifndef GOSLING
  443.         vscreen[currow].v_flag |= VFEXT | VFCHG;
  444. #else
  445.         vscreen[currow]->v_flag |= VFEXT | VFCHG;
  446. #endif
  447.         updext(currow, curcol);        /* and output extended line */
  448.     } else lbound = 0;            /* not extended line */
  449.  
  450.     /* make sure no lines need to be de-extended because 
  451.         * the cursor is no longer on them 
  452.         */
  453.     wp = wheadp;
  454.     while (wp != NULL) {
  455.         lp = wp->w_linep;
  456.         i = wp->w_toprow;
  457.         while (i < wp->w_toprow + wp->w_ntrows) {
  458.                 k = LINECOLOR(lp);
  459. #ifndef GOSLING
  460.                 if (k != vscreen[i].v_color)
  461.                   {
  462.                     if (showtouchedlines)    /* force */
  463.                       vscreen[i].v_flag |= (VFCHG|VFHBAD);
  464.                 vscreen[i].v_color = k;
  465.                   }
  466.         if (vscreen[i].v_flag & VFEXT) 
  467. #else
  468.                 if (k != vscreen[i]->v_color)
  469.                   {
  470.                     if (showtouchedlines)    /* force */
  471.                       vscreen[i]->v_flag |= (VFCHG|VFHBAD);
  472.                 vscreen[i]->v_color = k;
  473.                   }
  474.         if (vscreen[i]->v_flag & VFEXT) 
  475. #endif
  476.                   {
  477.             /* always flag extended lines as changed 
  478.                     */
  479. #ifndef GOSLING
  480.             vscreen[i].v_flag |= VFCHG;
  481. #else
  482.             vscreen[i]->v_flag |= VFCHG;
  483. #endif
  484.             if ((wp != curwp) || (lp != wp->w_dotp) ||
  485.                 (curcol < ncol - 1)) {
  486.             vtmove(i, 0);
  487.             for (j = 0; j < llength(lp); ++j)
  488.                 vtputc(lgetc(lp, j));
  489.             vteeol();
  490.             /* this line no longer is extended 
  491.                         */
  492. #ifndef GOSLING
  493.             vscreen[i].v_flag &= ~VFEXT;
  494. #else
  495.             vscreen[i]->v_flag &= ~VFEXT;
  496. #endif
  497.             }
  498.         }
  499.         lp = lforw(lp);
  500.         ++i;
  501.         }
  502.  
  503.         /* if whole screen garbaged, fix up mode lines 
  504.             */
  505.         if (sgarbf != FALSE)
  506. #ifndef GOSLING
  507.               vscreen[i].v_flag |= VFCHG;
  508. #else
  509.               vscreen[i]->v_flag |= VFCHG;
  510. #endif
  511.         /* and onward to the next window 
  512.             */
  513.         wp = wp->w_wndp;
  514.     }
  515.  
  516.     if (sgarbf != FALSE) {            /* Screen is garbage.    */
  517.         sgarbf = FALSE;            /* Erase-page clears    */
  518.         epresf = FALSE;            /* the message area.    */
  519.         tttop  = HUGEN;            /* Forget where you set */
  520.         ttbot  = HUGEN;            /* scroll region.    */
  521.         tthue  = CNONE;            /* Color unknown.    */
  522.         ttmove(0, 0);
  523.         tteeop();
  524.         for (i=0; i<nrow-1; ++i) {
  525. #ifndef GOSLING
  526.             uline(i, &vscreen[i], blanks);
  527.             ucopy(&vscreen[i], &pscreen[i]);
  528. #else
  529.             uline(i, vscreen[i], blanks);
  530.             ucopy(vscreen[i], pscreen[i]);
  531. #endif
  532.         }
  533.         ttmove(currow, curcol - lbound);
  534.         ttflush(FALSE);
  535.         return;
  536.     }
  537.  
  538. #ifdef    GOSLING    
  539.     if (hflag != FALSE) {            /* Hard update?        */
  540.         for (i=0; i<nrow-1; ++i) {    /* Compute hash data.    */
  541.             hash(vscreen[i]);
  542.             hash(pscreen[i]);
  543.         }
  544.         offs = 0;            /* Get top match.    */
  545.         while (offs != nrow-1) {
  546.             vp1 = vscreen[offs];
  547.             vp2 = pscreen[offs];
  548.             if (vp1->v_color != vp2->v_color
  549.             ||  vp1->v_hash     != vp2->v_hash)
  550.                 break;
  551.             uline(offs, vp1, vp2);
  552.             ucopy(vp1, vp2);
  553.             ++offs;
  554.         }
  555.         if (offs == nrow-1) {        /* Might get it all.    */
  556.             ttmove(currow, curcol - lbound);
  557.             ttflush(FALSE);
  558.             return;
  559.         }
  560.         size = nrow-1;            /* Get bottom match.    */
  561.         while (size != offs) {
  562.             vp1 = vscreen[size-1];
  563.             vp2 = pscreen[size-1];
  564.             if (vp1->v_color != vp2->v_color
  565.             ||  vp1->v_hash     != vp2->v_hash)
  566.                 break;
  567.             uline(size-1, vp1, vp2);
  568.             ucopy(vp1, vp2);
  569.             --size;
  570.         }
  571.         if ((size -= offs) == 0)    /* Get screen size.    */
  572.             panic("Illegal screen size in update");
  573.         setscores(offs, size);        /* Do hard update.    */
  574.         traceback(offs, size, size, size);
  575.         for (i=0; i<size; ++i)
  576.             ucopy(vscreen[offs+i], pscreen[offs+i]);
  577.         ttmove(currow, curcol - lbound);
  578.         ttflush(FALSE);
  579.         return;
  580.     }
  581. #endif
  582.     for (i=0; i<nrow-1; ++i) {        /* Easy update.        */
  583. #ifndef GOSLING
  584.         vp1 = &vscreen[i];
  585.         vp2 = &pscreen[i];
  586. #else
  587.         vp1 = vscreen[i];
  588.         vp2 = pscreen[i];
  589. #endif
  590.         if ((vp1->v_flag&VFCHG) != 0) {
  591.             uline(i, vp1, vp2);
  592.             ucopy(vp1, vp2);
  593.         }
  594.     }
  595.     ttmove(currow, curcol - lbound);
  596.     ttflush(FALSE);
  597. }
  598.  
  599. /*
  600.  * Update a saved copy of a line,
  601.  * kept in a VIDEO structure. The "vvp" is
  602.  * the one in the "vscreen". The "pvp" is the one
  603.  * in the "pscreen". This is called to make the
  604.  * virtual and physical screens the same when
  605.  * display has done an update.
  606.  */
  607. static VOID ucopy(vvp, pvp) 
  608. register VIDEO *vvp; 
  609. register VIDEO *pvp; 
  610. {
  611.  
  612.     vvp->v_flag &= ~VFCHG;            /* Changes done.    */
  613.     pvp->v_flag  = vvp->v_flag;        /* Update model.    */
  614. #ifdef GOSLING
  615.     pvp->v_hash  = vvp->v_hash;
  616.     pvp->v_cost  = vvp->v_cost;
  617. #endif
  618.     pvp->v_color = vvp->v_color;
  619.     bcopy(vvp->v_text, pvp->v_text, ncol);
  620. }
  621.  
  622. /* updext: update the extended line which the cursor is currently
  623.  * on at a column greater than the terminal width. The line
  624.  * will be scrolled right or left to let the user see where
  625.  * the cursor is
  626.  */
  627. VOID updext(currow, curcol)
  628. int currow, curcol;
  629. {
  630.     register LINE *lp;            /* pointer to current line */
  631.     register int j;            /* index into line */
  632.  
  633.     /* calculate what column the left bound should be 
  634.     * (force cursor into middle half of screen) 
  635.     */
  636.     lbound = curcol - (curcol % (ncol>>1)) - (ncol>>2);
  637.  
  638.     /* scan through the line outputing characters to the virtual screen 
  639.     * once we reach the left edge 
  640.     */
  641.     vtmove(currow, -lbound);            /* start scanning offscreen */
  642.     lp = curwp->w_dotp;                /* line to output */
  643.     for (j=0; j<llength(lp); ++j)        /* until the end-of-line */
  644.     vtpute(lgetc(lp, j));
  645.  
  646.     /* truncate the virtual line and put a '$' in column 1 
  647.     */
  648.     vteeol();
  649. #ifndef GOSLING
  650.     vscreen[currow].v_text[0] = '$';    
  651. #else                    
  652.     vscreen[currow]->v_text[0] = '$';    
  653. #endif
  654. }
  655.  
  656. /*
  657.  * Update a single line. This routine only
  658.  * uses basic functionality (no insert and delete character,
  659.  * but erase to end of line). The "vvp" points at the VIDEO
  660.  * structure for the line on the virtual screen, and the "pvp"
  661.  * is the same for the physical screen. Avoid erase to end of
  662.  * line when updating CMODE color lines, because of the way that
  663.  * reverse video works on most terminals.
  664.  *
  665.  * NOTE if defined, uses dump-whole-line since presumed fastest
  666.  */
  667. static VOID uline(row, vvp, pvp) 
  668. int row;
  669. register VIDEO *vvp; 
  670. register VIDEO *pvp; 
  671. {
  672. #ifdef CURSES
  673.         register char *vc, *pc;
  674.         register int i = 0;
  675.  
  676.     ttcolor(vvp->v_color);
  677.         ttmove(row, i); 
  678.     ttputline(&vvp->v_text[i]);           
  679. #else
  680.  
  681. # ifdef WINDOW_IO
  682.  
  683.         register char *vc, *pc;
  684.         register int i = 0;
  685.  
  686.         /* Find first diff char, then dump line from there to
  687.         * end. If not same color, must dump whole line vs
  688.         * only outputting from 'difference to end of line'.
  689.         * NOTE this code written on premise that dumping a
  690.         * whole line is faster than dumping even just 2 chars
  691.         * in that line if those 2 chars not contigious, ie one I/O per 
  692.         * line is fastest possible output means.  (JAM)
  693.         */
  694.         if (vvp->v_color == pvp->v_color)
  695.           {
  696.         vc = &vvp->v_text[0];
  697.         pc = &pvp->v_text[0];
  698.             while (vc[i] && (pc[i] == vc[i]))
  699.               i++;
  700.  
  701. #  ifdef MSW
  702.             /* Serious HACK - bug with truetype fonts (?) causes
  703.             * left-edge character droppings when drawing some chars
  704.             * on top of others, ie E on V leaves drops to left. This
  705.             * hack backs up one char; the previous char is the same
  706.             * in old and new line. This fixes the 'problem'. Sheesh (JAM)
  707.             */
  708.             if (i > 0)
  709.               i--;
  710. #  endif
  711.           }
  712.     ttcolor(vvp->v_color);
  713.         ttmove(row, i); 
  714.     ttputline(&vvp->v_text[i]);           
  715. # else /* WINDOW_IO */
  716.     register char    *cp1;
  717.     register char    *cp2;
  718.     register char    *cp3;
  719.     char        *cp4;
  720.     char        *cp5;
  721.     register int    nbflag;
  722.  
  723.     if (vvp->v_color != pvp->v_color) {    /* Wrong color, do a    */
  724.         ttmove(row, 0);            /* full redraw.        */
  725. #  ifdef    STANDOUT_GLITCH
  726.         if (pvp->v_color != CTEXT && SG >= 0) 
  727.                   tteeol();
  728. #  endif
  729.         ttcolor(vvp->v_color);
  730. #  ifdef    STANDOUT_GLITCH
  731.         cp1 = &vvp->v_text[SG > 0 ? SG : 0];
  732.         /* the odd code for SG==0 is to avoid putting the invisable
  733.          * glitch character on the next line.
  734.          * (Hazeltine executive 80 model 30)
  735.          */
  736.         cp2 = &vvp->v_text[ncol - (SG >= 0 ? (SG!=0 ? SG : 1) : 0)];
  737. #  else
  738.         cp1 = &vvp->v_text[0];
  739.         cp2 = &vvp->v_text[ncol];
  740. #  endif
  741.         while (cp1 != cp2) {
  742.             ttputc(*cp1++);
  743.             ++ttcol;
  744.         }
  745. #  ifndef MOVE_STANDOUT
  746.         ttcolor(CTEXT);
  747. #  endif
  748.         return;
  749.     }
  750.     cp1 = &vvp->v_text[0];            /* Compute left match.    */
  751.     cp2 = &pvp->v_text[0];
  752.     while (cp1!=&vvp->v_text[ncol] && cp1[0]==cp2[0]) {
  753.         ++cp1;
  754.         ++cp2;
  755.     }
  756.     if (cp1 == &vvp->v_text[ncol])        /* All equal.        */
  757.         return;
  758.     nbflag = FALSE;
  759.     cp3 = &vvp->v_text[ncol];        /* Compute right match. */
  760.     cp4 = &pvp->v_text[ncol];
  761.     while (cp3[-1] == cp4[-1]) {
  762.         --cp3;
  763.         --cp4;
  764.         if (cp3[0] != ' ')        /* Note non-blanks in    */
  765.             nbflag = TRUE;        /* the right match.    */
  766.     }
  767.     cp5 = cp3;                /* Is erase good?    */
  768.     if (nbflag==FALSE && vvp->v_color==CTEXT) {
  769.         while (cp5!=cp1 && cp5[-1]==' ')
  770.             --cp5;
  771.         /* Alcyon hack */
  772.         if ((int)(cp3-cp5) <= tceeol)
  773.             cp5 = cp3;
  774.     }
  775.     /* Alcyon hack */
  776.     ttmove(row, (int)(cp1-&vvp->v_text[0]));
  777. #  ifdef    STANDOUT_GLITCH
  778.     if (vvp->v_color != CTEXT && SG > 0) {
  779.         if(cp1 < &vvp->v_text[SG]) cp1 = &vvp->v_text[SG];
  780.         if(cp5 > &vvp->v_text[ncol-SG]) cp5 = &vvp->v_text[ncol-SG];
  781.     } else if (SG < 0)
  782. #  endif
  783.         ttcolor(vvp->v_color);
  784.     while (cp1 != cp5) {
  785.         ttputc(*cp1++);
  786.         ++ttcol;
  787.     }
  788.     if (cp5 != cp3)                /* Do erase.        */
  789.         tteeol();
  790. # endif /* WINDOW_IO */
  791. #endif /* CURSES */
  792. }
  793.  
  794. /*
  795.  * Redisplay the mode line for
  796.  * the window pointed to by the "wp".
  797.  * This is the only routine that has any idea
  798.  * of how the modeline is formatted. You can
  799.  * change the modeline format by hacking at
  800.  * this routine. Called by "update" any time
  801.  * there is a dirty window.
  802.  * Note that if STANDOUT_GLITCH is defined, first and last SG characters
  803.  * may never be seen.
  804.  */
  805. static VOID modeline(wp, activebp) 
  806. register EWINDOW *wp; 
  807. BOOL activebp;
  808. {
  809.     register int n;
  810.     register BUFFER *bp;
  811.     int mode;
  812.         int flag;
  813.         char fchar = (activebp ? '-' : ' ');
  814.  
  815.     n = wp->w_toprow+wp->w_ntrows;        /* Location.        */
  816. #ifndef GOSLING
  817.     vscreen[n].v_color = CMODE;        /* Mode line color.    */
  818.     vscreen[n].v_flag |= (VFCHG|VFHBAD);    /* Recompute, display.    */
  819. #else
  820.     vscreen[n]->v_color = CMODE;        /* Mode line color.    */
  821.     vscreen[n]->v_flag |= (VFCHG|VFHBAD);    /* Recompute, display.    */
  822. #endif
  823.     vtmove(n, 0);                /* Seek to right line.    */
  824.  
  825.         /* reset n, now a column counter
  826.         */
  827.         n = 0;
  828.     bp = wp->w_bufp;
  829.     flag = ((bp->b_flag & BFCHG) ? TRUE : FALSE);     /* "*" if changed. */
  830.     vtputc(fchar);  n++;
  831.  
  832.         if (somemail)
  833.           {
  834.             n += vtputs(" Mail ");
  835.         vtputc(fchar);  n++;
  836.           }
  837.  
  838. #ifndef WINDOWED
  839.        if (activebp)
  840.          n += vtputs(g_APPNAME);
  841.        else
  842.          {
  843.            n = strlen(g_APPNAME);
  844.            vtputb(' ', n);
  845.          }
  846.        vtputc(fchar);  n++;       
  847. #endif
  848.  
  849.     if ((bp->b_flag&BFVIEW) != 0)     /* "r" if readonly. */
  850.        vtputc('%'); 
  851.         else if (flag)
  852.        vtputc('*'); 
  853.     else
  854.        vtputc(fchar); 
  855.         n++;
  856.  
  857.         if (flag && !(bp->b_flag & BFINC) &&   /* tells if incremental save */
  858.         bp->b_fname[0])
  859.       vtputc('+');                         /* up-to-date */
  860.         else if (flag && bp->b_fname[0])
  861.           vtputc('!');                         /* changes not flushed */
  862.         else
  863.           vtputc(fchar);               /* no changes, ok */
  864.         n++;
  865.  
  866.     vtputb(fchar, 2); n += 2;
  867.  
  868.     if (bp->b_bname[0] != '\0')
  869.       n += vtputs(&(bp->b_bname[0]));
  870.  
  871. #ifndef SHOWFILENAME            /* jam.h */
  872. # define MODE_OFFSET 25
  873. # else
  874. # define MODE_OFFSET 62
  875.         if (bp->b_fname[0] != '\0')
  876.           {
  877.            int x = strlen(bp->b_fname);
  878.  
  879.            vtputb(' ', 3); 
  880.            n += 3;
  881.            if (x <= MAX_FNAME_CHARS)
  882.          n += vtputs(&(bp->b_fname[0]));
  883.            else
  884.              {
  885.                char buf[MIN_FNAME_CHARS];
  886.  
  887.                bzero(buf, MIN_FNAME_CHARS);
  888.                vtputb('.', 2); n += 2;
  889.                x = MIN_FNAME_CHARS + (x - MAX_FNAME_CHARS);
  890.                n += vtputs(&bp->b_fname[x]);
  891.              }
  892.           vtputc(' '); n++; 
  893.  
  894. #ifdef DOCRYPT
  895.            if (bp->b_flag & BFCRYPT)
  896.              {
  897.                static char *key = "(Key!)";
  898.                n += vtputs(key);
  899.              }
  900. #endif /* CRYPT */
  901.            vtputc(' '); n++; 
  902.           }
  903. #endif
  904.  
  905.     while (n < MODE_OFFSET)
  906.           {    
  907.         vtputc(' ');
  908.         n++;
  909.       }
  910.  
  911.         if (activebp)
  912.           {
  913.         vtputc('('); n++;
  914.         for (mode=0; ;)
  915.               {
  916.                 n += vtputs(bp->b_modes[mode]->p_name);
  917.                 if ((bp->b_modes[mode] == name_mode("C")) && isCindent())
  918.                   {
  919.                     vtputc('!');
  920.                     n++;
  921.                   }
  922.                if(++mode > bp->b_nmodes) 
  923.                  break;
  924.                vtputc('-'); n++;
  925.               }
  926.         vtputc(')'); n++;
  927.           }
  928.  
  929.     while (n < ncol) 
  930.       {            /* Pad out.        */
  931.            if ((n == 79) && activebp)    /* count from 0 */
  932.              vtputc('^');        /* 80 col marker */
  933.            else
  934.          vtputc(fchar);
  935.        n++;
  936.       }
  937. }
  938. /*
  939.  * output a string, report how long it was.
  940.  */
  941. vtputs(s) 
  942. register char *s; 
  943. {
  944.   register int n = 0;
  945.  
  946.   while (*s != '\0') 
  947.     {
  948.       vtputc(*s++);
  949.       ++n;
  950.     }
  951.    return n;
  952. }
  953. #ifdef    GOSLING
  954. /*
  955.  * Compute the hash code for
  956.  * the line pointed to by the "vp". Recompute
  957.  * it if necessary. Also set the approximate redisplay
  958.  * cost. The validity of the hash code is marked by
  959.  * a flag bit. The cost understand the advantages
  960.  * of erase to end of line. Tuned for the VAX
  961.  * by Bob McNamara; better than it used to be on
  962.  * just about any machine.
  963.  */
  964. static VOID hash(vp)
  965. register VIDEO *vp; 
  966. {
  967.     register int    i;
  968.     register int    n;
  969.     register char    *s;
  970.  
  971.     if ((vp->v_flag&VFHBAD) != 0) {        /* Hash bad.        */
  972.         s = &vp->v_text[ncol-1];
  973.         for (i=ncol; i!=0; --i, --s)
  974.             if (*s != ' ')
  975.                 break;
  976.         n = ncol-i;            /* Erase cheaper?    */
  977.         if (n > tceeol)
  978.             n = tceeol;
  979.         vp->v_cost = i+n;        /* Bytes + blanks.    */
  980.         for (n=0; i!=0; --i, --s)
  981.             n = (n<<5) + n + *s;
  982.         vp->v_hash = n;            /* Hash code.        */
  983.         vp->v_flag &= ~VFHBAD;        /* Flag as all done.    */
  984.     }
  985. }
  986.  
  987. /*
  988.  * Compute the Insert-Delete
  989.  * cost matrix. The dynamic programming algorithm
  990.  * described by James Gosling is used. This code assumes
  991.  * that the line above the echo line is the last line involved
  992.  * in the scroll region. This is easy to arrange on the VT100
  993.  * because of the scrolling region. The "offs" is the origin 0
  994.  * offset of the first row in the virtual/physical screen that
  995.  * is being updated; the "size" is the length of the chunk of
  996.  * screen being updated. For a full screen update, use offs=0
  997.  * and size=nrow-1.
  998.  *
  999.  * Older versions of this code implemented the score matrix by
  1000.  * a two dimensional array of SCORE nodes. This put all kinds of
  1001.  * multiply instructions in the code! This version is written to
  1002.  * use a linear array and pointers, and contains no multiplication
  1003.  * at all. The code has been carefully looked at on the VAX, with
  1004.  * only marginal checking on other machines for efficiency. In
  1005.  * fact, this has been tuned twice! Bob McNamara tuned it even
  1006.  * more for the VAX, which is a big issue for him because of
  1007.  * the 66 line X displays.
  1008.  *
  1009.  * On some machines, replacing the "for (i=1; i<=size; ++i)" with
  1010.  * i = 1; do { } while (++i <=size)" will make the code quite a
  1011.  * bit better; but it looks ugly.
  1012.  */
  1013. static VOID setscores(offs, size) 
  1014. int offs, size;
  1015. {
  1016.     register SCORE    *sp;
  1017.     SCORE        *sp1;
  1018.     register int    tempcost;
  1019.     register int    bestcost;
  1020.     register int    j;
  1021.     register int    i;
  1022.     register VIDEO    **vp;
  1023.     VIDEO        **pp, **vbase, **pbase;
  1024.  
  1025.     vbase = &vscreen[offs-1];        /* By hand CSE's.    */
  1026.     pbase = &pscreen[offs-1];
  1027.  
  1028.     score[0].s_itrace = 0;            /* [0, 0]        */
  1029.     score[0].s_jtrace = 0;
  1030.     score[0].s_cost      = 0;
  1031.     sp = &score[1];                /* Row 0, inserts.    */
  1032.     tempcost = 0;
  1033.     vp = &vbase[1];
  1034.     for (j=1; j<=size; ++j) {
  1035.         sp->s_itrace = 0;
  1036.         sp->s_jtrace = (XCHAR)(j-1);
  1037.         tempcost += tcinsl;
  1038.         tempcost += (*vp)->v_cost;
  1039.         sp->s_cost = tempcost;
  1040.         ++vp;
  1041.         ++sp;
  1042.     }
  1043.     sp = &score[NROW];            /* Column 0, deletes.    */
  1044.     tempcost = 0;
  1045.     for (i=1; i<=size; ++i) {
  1046.         sp->s_itrace = (XCHAR)(i-1);
  1047.         sp->s_jtrace = 0;
  1048.         tempcost  += tcdell;
  1049.         sp->s_cost = tempcost;
  1050.         sp += NROW;
  1051.     }
  1052.     sp1 = &score[NROW+1];            /* [1, 1].        */
  1053.     pp = &pbase[1];
  1054.     for (i=1; i<=size; ++i) {
  1055.         sp = sp1;
  1056.         vp = &vbase[1];
  1057.         for (j=1; j<=size; ++j) {
  1058.             sp->s_itrace = (XCHAR)(i-1);
  1059.             sp->s_jtrace = (XCHAR)j;
  1060.             bestcost = (sp-NROW)->s_cost;
  1061.             if (j != size)        /* Cd(A[i])=0 @ Dis.    */
  1062.                 bestcost += tcdell;
  1063.             tempcost = (sp-1)->s_cost;
  1064.             tempcost += (*vp)->v_cost;
  1065.             if (i != size)        /* Ci(B[j])=0 @ Dsj.    */
  1066.                 tempcost += tcinsl;
  1067.             if (tempcost < bestcost) {
  1068.                 sp->s_itrace = (XCHAR)i;
  1069.                 sp->s_jtrace = (XCHAR)(j-1);
  1070.                 bestcost = tempcost;
  1071.             }
  1072.             tempcost = (sp-NROW-1)->s_cost;
  1073.             if ((*pp)->v_color != (*vp)->v_color
  1074.             ||  (*pp)->v_hash  != (*vp)->v_hash)
  1075.                 tempcost += (*vp)->v_cost;
  1076.             if (tempcost < bestcost) {
  1077.                 sp->s_itrace = (XCHAR)(i-1);
  1078.                 sp->s_jtrace = (XCHAR)(j-1);
  1079.                 bestcost = tempcost;
  1080.             }
  1081.             sp->s_cost = bestcost;
  1082.             ++sp;            /* Next column.        */
  1083.             ++vp;
  1084.         }
  1085.         ++pp;
  1086.         sp1 += NROW;            /* Next row.        */
  1087.     }
  1088. }
  1089.  
  1090. /*
  1091.  * Trace back through the dynamic programming cost
  1092.  * matrix, and update the screen using an optimal sequence
  1093.  * of redraws, insert lines, and delete lines. The "offs" is
  1094.  * the origin 0 offset of the chunk of the screen we are about to
  1095.  * update. The "i" and "j" are always started in the lower right
  1096.  * corner of the matrix, and imply the size of the screen.
  1097.  * A full screen traceback is called with offs=0 and i=j=nrow-1.
  1098.  * There is some do-it-yourself double subscripting here,
  1099.  * which is acceptable because this routine is much less compute
  1100.  * intensive then the code that builds the score matrix!
  1101.  */
  1102. static VOID traceback(offs, size, i, j) 
  1103. int offs, size, i, j; 
  1104. {
  1105.     register int    itrace;
  1106.     register int    jtrace;
  1107.     register int    k;
  1108.     register int    ninsl;
  1109.     register int    ndraw;
  1110.     register int    ndell;
  1111.  
  1112.     if (i==0 && j==0)            /* End of update.    */
  1113.         return;
  1114.     itrace = score[(NROW*i) + j].s_itrace;
  1115.     jtrace = score[(NROW*i) + j].s_jtrace;
  1116.     if (itrace == i) {            /* [i, j-1]        */
  1117.         ninsl = 0;            /* Collect inserts.    */
  1118.         if (i != size)
  1119.             ninsl = 1;
  1120.         ndraw = 1;
  1121.         while (itrace!=0 || jtrace!=0) 
  1122.           {
  1123.           if (score[(NROW*itrace) + jtrace].s_itrace != (XCHAR)itrace)
  1124.             break;
  1125.           jtrace = (int)score[(NROW*itrace) + jtrace].s_jtrace;
  1126.           if (i != size)
  1127.             ++ninsl;
  1128.           ++ndraw;
  1129.         }
  1130.         traceback(offs, size, itrace, jtrace);
  1131.         if (ninsl != 0) {
  1132.             ttcolor(CTEXT);
  1133.             ttinsl(offs+j-ninsl, offs+size-1, ninsl);
  1134.         }
  1135.         do {                /* B[j], A[j] blank.    */
  1136.             k = offs+j-ndraw;
  1137.             uline(k, vscreen[k], blanks);
  1138.         } while (--ndraw);
  1139.         return;
  1140.     }
  1141.     if (jtrace == j) {            /* [i-1, j]        */
  1142.         ndell = 0;            /* Collect deletes.    */
  1143.         if (j != size)
  1144.             ndell = 1;
  1145.         while (itrace!=0 || jtrace!=0) 
  1146.           {
  1147.           if (score[(NROW*itrace) + jtrace].s_jtrace != (XCHAR)jtrace)
  1148.             break;
  1149.           itrace = (int)score[(NROW*itrace) + jtrace].s_itrace;
  1150.           if (j != size)
  1151.             ++ndell;
  1152.         }
  1153.         if (ndell != 0) {
  1154.             ttcolor(CTEXT);
  1155.             ttdell(offs+i-ndell, offs+size-1, ndell);
  1156.         }
  1157.         traceback(offs, size, itrace, jtrace);
  1158.         return;
  1159.     }
  1160.     traceback(offs, size, itrace, jtrace);
  1161.     k = offs+j-1;
  1162.     uline(k, vscreen[k], pscreen[offs+i-1]);
  1163. }
  1164. #endif /* GOSLING */
  1165.  
  1166. /* put N copies of char c
  1167. */
  1168. static int vtputb(c, n)
  1169. char c;
  1170. int n;
  1171. {
  1172.   register int i = n;
  1173.  
  1174.   while (i)
  1175.     {
  1176.       vtputc(c);
  1177.       i--;
  1178.     }
  1179.   return(n);
  1180. }
  1181.